from functools import partial

from .odoorpc import OdooRpcModel


class BaseModelForOdoojs(object):
    _metadata = {}

    def __init__(self, model, env, metadata=None):
        self.model = model
        self.env = env
        self.rpc = env.rpc
        self.metadata = metadata or {}

        self.odoorpc = OdooRpcModel(model, env)

    @classmethod
    def _get_metadata(cls):
        return cls._metadata or {}

    @property
    def session(self):
        return self.rpc.session

    @property
    def allowed_company_id(self):
        return self.env.allowed_company_id

    @allowed_company_id.setter
    def allowed_company_id(self, value):
        self.env.allowed_company_id = value

    def __getattr__(self, attr):
        return partial(self.call, attr)

    def __getitem__(self, attr):
        if hasattr(self, attr):
            return getattr(self, attr)

        return partial(self.call, attr)


class ModelClassMeta(BaseModelForOdoojs):
    def call(self, method, *args, context=None, **kwargs):
        context = kwargs.get('context', {})
        context = self.get_context(context)
        return self.odoorpc.rpccall(method, *args, context=context, **kwargs)

    def get_context(self, context=None):
        if not context:
            context = {}
        user_context = self.session['user_context']
        context2 = dict({}, **user_context)
        context2.update({'allowed_company_ids': [self.allowed_company_id]})
        meta_context = self.metadata.get('context', {})

        def fn(v):
            # print(v,  type(v))
            if callable(v):
                return v(self)
            return v

        meta_context = dict((k, fn(v)) for k, v in meta_context.items())

        context2.update(meta_context)
        context2.update(context)
        return context2


class ModelClassBase(ModelClassMeta):
    pass


class ModelClassCrud(ModelClassBase):
    def web_search_read(self, domain=None, context=None):
        print('in modlejs, search', domain)
        context = self.get_context(context)
        fields = list(self.metadata.get('fieldsForSearch', {}).keys())
        return self.rpc.web_dataset_search_read(
            self.model, domain, fields=fields, context=context)

    # def search(self, domain=None, context=None):
    #     print('in modlejs, search', domain)
    #     context = self.get_context(context)
    #     fields = list(self.metadata.get('fieldsForSearch', {}).keys())

    #     return self.odoorpc.search_read2(domain, fields=fields, context=context)

    def browse(self, rid, fields=None, isEdit=None, context=None):
        context = self.get_context(context)
        if not fields:
            if isEdit:
                fields = self.metadata.get('fieldsForBrowse', {})
            else:
                fields = self.metadata.get('fieldsForBrowse', {})

            fields = list(fields.keys())

        return self.odoorpc.read2(rid, fields=fields, context=context)

    def browse_one(self, rid, fields=None, isEdit=None, context=None):
        res = self.browse(rid, fields=fields, isEdit=isEdit, context=context)
        return res and res[0] or {}

    def search_one(self, domain, fields=None):
        res = self.search_read2(domain, fields=fields, limit=1)
        if res:
            return res[0]
        else:
            return {}

    def create(self, values, context=None):
        context = self.get_context(context)
        fields = self.metadata.get('fieldsForBrowse', {})
        return self.odoorpc.create2(values, fields=fields, context=context)

    def write(self, rid, values, context=None):
        context = self.get_context(context)
        fields = self.metadata.get('fieldsForBrowse', {})
        return self.odoorpc.write2(rid, values, fields=fields, context=context)


class ModelClassNew(ModelClassCrud):
    def get_globals_dict(self, values, globals_dict=None):
        # to be override, to set globals_dict
        return globals_dict or {}

    def fields_get2(self, fields=None, attributes=None,
                    fields_type=None, globals_dict=None, context=None):
        context = self.get_context(context)

        if fields:
            pass
        elif fields_type == 'search':
            fields = self.metadata.get('fieldsForSearch', {})
        elif fields_type == 'test':
            fields = []
        # elif fields_type == 'browse':
        #     fields.update(self.metadata.get('fieldsForBrowse', {}))
        else:
            fields = self.metadata.get('fieldsForBrowse', {})

        if not isinstance(fields, list):
            fields = list(fields.keys())

        # print('---in feilds get,', self.metadata)

        if not globals_dict:
            globals_dict = {}

        result = self.odoorpc.fields_get2(
            fields, ['type', 'selection', 'relation', 'domain'],
            globals_dict=globals_dict)

        for k, v in result.items():
            if v['type'] in ['selection']:
                # print(' --- in modelsjs fields_get,', k)
                # print(k, v)
                v['options'] = v['selection']
                # v['options'] = [{'value': sel[0], 'text': sel[1], 'label': sel[1]}
                #                 for sel in v['selection']]

        # print(' --- in modelsjs fields_get,2 ', result)

        return result

    def default_get_onchange(self, values={}, context=None):
        # print('--in--modeljs--,default_get_onchange ', context)
        context = self.get_context(context)
        fields = self.metadata['fieldsForBrowse']
        # fields = list(fields.keys())

        res = self.onchange2(
            [], values, [], {}, fields_default_get=fields, context=context)
        # print('--in models, default_get_onchange', res)
        return res

    def onchange2(self, ids, values, field_name, field_onchange=None,
                  fields_default_get=None, context=None):
        # print('--in--modeljs--,onchange2 1 ', context)
        context = self.get_context(context)
        # print('--in--modeljs--,onchange2 2 ', context)

        if not field_onchange:
            field_onchange = self.metadata['field_onchange']

        if isinstance(field_name, str) and not (field_name in field_onchange and field_onchange[field_name]):
            return {'domain': {}, 'value': {}, 'fields': {}}
        else:
            res = self.odoorpc.onchange2(
                ids, values, field_name, field_onchange,
                fields_default_get=fields_default_get, context=context)

            return res


class ModelClassWorkflow(ModelClassNew):
    pass


class ModelClassImportExport(ModelClassWorkflow):
    # 基本的扩展
    def export_file(self, ids, domain, file_extension=None):
        import_export = self.metadata['import_export']
        model = import_export['model']
        fields = import_export.get('fields_export')
        if not fields:
            fields = import_export['fields']
            fields = [{'name': fld, 'label': fld} for fld in fields]
        context = {
            "allowed_company_ids": [1],
            "lang": "zh_CN", "tz": "Asia/Shanghai", "uid": 2,
        }

        data = {"model": model, "fields": fields,
                "ids": ids, "domain": domain, "groupby": [],
                "import_compat": False,
                "context": context,
                }

        fn = file_extension == 'xlsx' and self.rpc.xlsx_export or self.rpc.csv_export
        return fn(data)

    def import_create(self):
        context = self.metadata.get('context', {})
        import_export = self.metadata['import_export']
        model = import_export['model']
        import_obj = self.env['base_import.import']
        import_id = import_obj.create({"res_model": model}, context=context)
        return import_id

    def import_set_file(self, import_id, fp):
        res = self.rpc.base_import_set_file(import_id, fp)
        return res

    def import_do(self, import_id, fp):
        context = self.metadata.get('context', {})
        import_export = self.metadata['import_export']
        fields = import_export['fields']
        columns = import_export['fields']
        name_create_enabled_fields = import_export.get(
            'name_create_enabled_fields', {})

        options = {"headers": True,
                   "advanced": False,
                   "keep_matches": False,
                   "name_create_enabled_fields": name_create_enabled_fields,
                   "skip": 0,
                   "limit": 2000,
                   "encoding": "",
                   "separator": "",
                   "quoting": "\"",
                   "date_format": "%Y-%m-%d",
                   "datetime_format": "%Y-%m-%d %H:%M:%S",
                   "float_thousand_separator": ",",
                   "float_decimal_separator": ".",
                   "fields": []
                   }

        import_obj = self.env['base_import.import']
        res = import_obj.do(
            import_id, fields, columns, options, context=context)

        return res

    # 不再用了, 仅在 SP3 中 使用一次 2020-10-21
    def import_base64(self, file_name, file_base64, file_type):
        context = self.metadata['context']

        import_export = self.metadata['import_export']
        model = import_export['model']
        fields = import_export['fields']
        columns = import_export['fields']
        name_create_enabled_fields = import_export.get(
            'name_create_enabled_fields', {})

        options = {"headers": True,
                   "advanced": False,
                   "keep_matches": False,
                   "name_create_enabled_fields": name_create_enabled_fields,
                   "skip": 0,
                   "limit": 2000,
                   "encoding": "",
                   "separator": "",
                   "quoting": "\"",
                   "date_format": "%Y-%m-%d",
                   "datetime_format": "%Y-%m-%d %H:%M:%S",
                   "float_thousand_separator": ",",
                   "float_decimal_separator": ".",
                   "fields": []
                   }

        import_obj = self.env['base_import.import']

        return import_obj._import_base64(
            file_name, file_base64, file_type,
            model, fields, columns, options, context=context)

    # 不再用了, 直接用 官方的 /web/export/csv
    def export_base64(self, ids, fields=None, file_extension=None):
        if not fields:
            import_export = self.metadata['import_export']
            fields = import_export.get('fields_export')
            if not fields:
                fields = import_export['fields']
        return self.call('export_base64', ids, fields, file_extension=file_extension)


class ModelClassReport(ModelClassImportExport):
    pass


class Model(ModelClassReport):
    pass

    def test_import_file(self, path):
        # create wizard
        import_id = self.import_create()
        print('import_id,', import_id)

        with open(path, "rb") as fp:
            print('fp,', fp)
            print('fp,', fp.name)

            # 上传文件 到 wizard
            res = self.import_set_file(import_id, fp)
            print('set_file,', res)

            # 执行加载
            return self.import_do(import_id, fp)

    def js_write_file(self, path, base64str):
        file_bytes = base64.b64decode(bytes(base64str, encoding='utf8'))

        print('file_bytes, ', file_bytes)
        # with open(path, "wb") as fp:
        #     fp.write(file_bytes)

    def js_read_file_base64(self, path):
        with open(path, "rb") as fp:
            raw = fp.read()
            base64str = str(base64.b64encode(raw), encoding='utf8')
            # print('sss,', base64str)
            return base64str

    def get_content_type(self, filename):
        types = {
            'csv': 'text/csv',
            'xls': 'application/vnd.ms-excel',
            'xlsx': 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
        }
        content_type = types[filename.split('.')[-1]]
        return content_type
